import time

from dateutil.parser import parse
import json
import logging
import traceback

import rel
import websocket

from model.ReqRouterCommandEnum import ReqRouterCommandEnum
from model.WebsocketClientVO import WebsocketClientVO
from service.ArpService import ArpService
from service.ClashService import ClashService
from service.UploadDataService import UploadDataService


class ClashWebsocketClientService:
    def __init__(self, clientVo: WebsocketClientVO):
        self.ws = None
        self.clientVo = clientVo
        self.serverWs = self.clientVo.serverWs
        self.arpService = ArpService(clientVo)
        self.updateDataService = UploadDataService(clientVo)
        self.clashService = ClashService(clientVo)


    def onMessage(self, ws, message):
        try:
            if not message:
                return
            data = json.loads(message)
            if 'connections' not in data:
                return
            result =[]
            for k in data['connections']:
                ip = k['metadata']['sourceIP']
                mac = self.arpService.read(ip)
                startTime = parse(k['start'])
                startTimeStr = startTime.strftime("%Y-%m-%d %H:%M:%S")
                if not mac:
                    continue
                if not k['id']:
                    continue
                a = {
                    'upload': k['upload'],
                    'download': k['download'],
                    'ip': ip,
                    'mac': mac,
                    'port': k['metadata']['sourcePort'],
                    'target_host': k['metadata']['host'],
                    'target_ip': k['metadata']['destinationIP'],
                    'target_port': k['metadata']['destinationPort'],
                    'proxy': "_".join(k['chains']),
                    'connect_id': k['id'],
                    'time': startTimeStr,
                    'device_id': self.clientVo.clientInfo,
                }
                result.append(a)
            if result.__len__() == 0:
                return
            self.updateDataService.upload(
                result, ReqRouterCommandEnum.UPLOAD_CLASH_CONNECTS
            )
        except Exception as e:
            traceback.print_exc()


    def onError(self, ws, error):
        print(f"发生错误: {error}")

    def onClose(self, ws, closeStatusCode, closeMsg):
        print("连接已关闭")
        self.start()

    def onOpen(self, ws):
        pass


    def start(self):
        while True:
            try:
                target = self.clientVo.clashHost.replace("http", "ws") + 'connections?token={}&level=info'.format(
                    self.clientVo.clashToken)
                self.ws = websocket.WebSocketApp(target,
                                                 on_open=self.onOpen,
                                                 on_message=self.onMessage,
                                                 on_error=self.onError,
                                                 on_close=self.onClose,
                                                 )
                self.clientVo.clashWs = self.ws
                self.ws.run_forever(dispatcher=rel, reconnect=5)
                break
            except Exception as e:
                logging.exception(e)
                time.sleep(30)